package com.authsphere.security.authorization;

import com.authsphere.security.common.configurers.AbstractAuthSphereAuthenticationFilterConfigurer;
import com.authsphere.security.token.common.AuthenticationTokenServices;
import com.authsphere.security.token.common.codec.DefaultBase64Codec;
import com.authsphere.security.token.common.codec.TokenCodec;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

/**
 * @program: AuthSphere
 * @description:
 * @author: YuKai Fan
 * @create: 2025/3/13 10:08
 **/
public class AuthorizationTokenConfigurer<H extends HttpSecurityBuilder<H>> extends
        AbstractAuthSphereAuthenticationFilterConfigurer<H, AuthorizationTokenConfigurer<H>, AuthorizationTokenFilter> {

    private String tokenHeader = HttpHeaders.AUTHORIZATION;

    private TokenCodec tokenCodec = new DefaultBase64Codec();

    private String processingUrl;

    public AuthorizationTokenConfigurer() {
        super(UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
        return new AntPathRequestMatcher(loginProcessingUrl, "POST");
    }

    @Override
    public void init(H http) throws Exception {
        AuthorizationTokenFilter authenticationFilter = new AuthorizationTokenFilter();
        authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
        authenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
        authenticationFilter.setAuthenticationTokenServices(http.getSharedObject(AuthenticationTokenServices.class));
        if (StringUtils.isNotBlank(tokenHeader)) {
            authenticationFilter.setTokenHeader(tokenHeader);
        }
        if (StringUtils.isNotBlank(processingUrl)) {
            authenticationFilter.setFilterProcessesUrl(processingUrl);
        }
        authenticationFilter.setTokenCodec(tokenCodec);
        this.setAuthenticationFilter(authenticationFilter);
        AuthenticationTokenServices authenticationTokenServices = getAuthenticationTokenServices();
        http.setSharedObject(AuthenticationTokenServices.class, authenticationTokenServices);
        AuthorizationTokenAuthenticationProvider authorizationTokenAuthenticationProvider = new AuthorizationTokenAuthenticationProvider(authenticationTokenServices);
        http.authenticationProvider(this.postProcess(authorizationTokenAuthenticationProvider));
    }

    public void tokenHeader(String tokenHeader) {
        this.tokenHeader = tokenHeader;
    }

    public AuthorizationTokenConfigurer<H> processingUrl(String processingUrl) {
        this.processingUrl = processingUrl;
        return this;
    }

    public AuthorizationTokenConfigurer<H> tokenCodec(TokenCodec tokenCodec) {
        this.tokenCodec = tokenCodec;
        return this;
    }

    private AuthenticationTokenServices getAuthenticationTokenServices() {
        ResolvableType type = ResolvableType.forType(AuthenticationTokenServices.class);
        AuthenticationTokenServices bean = getBeanOrNull(type);
        return (bean != null) ? bean : new DefaultTokenServices();
    }



}
